"use strict";
/**
 * @ Author: Yoann Meclot. MSay2
 * @ Created on: 2021-06-14 17:49:33
 * @ Modified on: 2021-06-14 17:57:22
 */
/**
 * Copyright (c) 2020-2021 MSay2 (Yoann Meclot) - @msay2/tspoet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    privateMap.set(receiver, value);
    return value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return privateMap.get(receiver);
};
var _mAfter, _mBefore, _mIndex, _mMax, _mEnries, _mPool, _mFirst, _mLast, _mSize, _mCapacity;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HashSetPool = void 0;
const Exceptions_js_1 = require("../Exceptions.js");
const Objects_js_1 = require("../Objects.js");
const StringBuilder_js_1 = require("../StringBuilder.js");
const Arrays_js_1 = require("./Arrays.js");
const SetPool_js_1 = require("./SetPool.js");
class EntrySet {
    constructor(first, max) {
        _mAfter.set(this, void 0);
        _mBefore.set(this, void 0);
        _mIndex.set(this, void 0);
        _mMax.set(this, void 0);
        __classPrivateFieldSet(this, _mAfter, first);
        __classPrivateFieldGet(this, _mBefore) == undefined;
        __classPrivateFieldSet(this, _mIndex, 0);
        __classPrivateFieldSet(this, _mMax, max);
    }
    [(_mAfter = new WeakMap(), _mBefore = new WeakMap(), _mIndex = new WeakMap(), _mMax = new WeakMap(), Symbol.iterator)]() {
        return {
            next: () => {
                if (__classPrivateFieldGet(this, _mIndex) < __classPrivateFieldGet(this, _mMax)) {
                    if (__classPrivateFieldGet(this, _mAfter) != undefined) {
                        __classPrivateFieldSet(this, _mIndex, +__classPrivateFieldGet(this, _mIndex) + 1);
                        __classPrivateFieldSet(this, _mBefore, __classPrivateFieldGet(this, _mAfter));
                        __classPrivateFieldSet(this, _mAfter, __classPrivateFieldGet(this, _mAfter).mAfter);
                        return {
                            value: __classPrivateFieldGet(this, _mBefore),
                            done: false
                        };
                    }
                    else
                        throw new Exceptions_js_1.NullPointerException("Entry == undefined");
                }
                return {
                    value: undefined,
                    done: true
                };
            },
        };
    }
}
class HashSetPool {
    constructor(set) {
        _mEnries.set(this, undefined);
        _mPool.set(this, undefined);
        _mFirst.set(this, undefined);
        _mLast.set(this, undefined);
        _mSize.set(this, -1);
        _mCapacity.set(this, 0);
        if (set instanceof HashSetPool) {
            this.init(set.capacity());
            this.putAll(set);
            return;
        }
        if ((typeof set) == "number")
            this.init(set);
        else
            this.init(16);
    }
    put(value) {
        for (let entry = __classPrivateFieldGet(this, _mFirst); entry != undefined; entry = entry.mAfter) {
            if (value instanceof Object && "equals" in value) {
                let v = value;
                if (v.equals(entry.mValue))
                    return false;
            }
            else {
                if (value == entry.mValue)
                    return false;
            }
        }
        this.putEntry(value);
        return true;
    }
    putAll(set) {
        for (let entry of set.entrySet()) {
            if (!(__classPrivateFieldGet(this, _mSize) >= __classPrivateFieldGet(this, _mCapacity)))
                this.putEntry(entry.mValue);
        }
    }
    get(index) {
        if (index > __classPrivateFieldGet(this, _mSize))
            throw new Exceptions_js_1.IllegalStateException(`Index=[${index}] size=[${__classPrivateFieldGet(this, _mSize)}]`);
        let entry = this.obtainEntry(index);
        while (entry != undefined) {
            if (this.indexHash(index) == entry.mIndex)
                return entry.mValue;
            entry = entry.mNext;
        }
        return undefined;
    }
    getEntryAt(index) {
        let entry = this.obtainEntry(index);
        while (entry != undefined) {
            if (this.indexHash(index) == entry.mIndex)
                return entry;
            entry = entry.mNext;
        }
        return undefined;
    }
    set(index, value) {
        if (index > __classPrivateFieldGet(this, _mSize))
            throw new Exceptions_js_1.IllegalStateException(`Index=[${index}] size=[${__classPrivateFieldGet(this, _mSize)}]`);
        let entry = this.obtainEntry(index);
        while (entry != undefined) {
            if (this.indexHash(index) == entry.mIndex)
                entry.mValue = value;
            entry = entry.mNext;
        }
    }
    contains(value) {
        for (let entry = __classPrivateFieldGet(this, _mFirst); entry != undefined; entry = entry.mAfter) {
            if (value instanceof Object && "equals" in value) {
                let v = value;
                if (v.equals(entry.mValue))
                    return true;
            }
            else {
                if (value == entry.mValue)
                    return true;
            }
        }
        return false;
    }
    remove(index) {
        let entry = this.obtainEntry(index);
        while (entry != undefined) {
            if (this.indexHash(index) == entry.mIndex) {
                let prev = entry.mValue;
                this.removeEntry(entry);
                return prev;
            }
            entry = entry.mNext;
        }
        return undefined;
    }
    sort(comparable) {
        let array = this.toArray();
        Arrays_js_1.Arrays.sort(array, 0, array.length, comparable);
        for (let i = 0; i < __classPrivateFieldGet(this, _mSize); i++)
            this.set(i, array[i]);
    }
    filter(filter) {
        let set = new HashSetPool();
        for (let entry = __classPrivateFieldGet(this, _mFirst); entry != null; entry = entry.mAfter) {
            if (filter.accept(entry.mValue))
                set.put(entry.mValue);
        }
        return set;
    }
    entrySet() {
        return new EntrySet(__classPrivateFieldGet(this, _mFirst), __classPrivateFieldGet(this, _mSize));
    }
    clear() {
        for (let entry = __classPrivateFieldGet(this, _mFirst); entry != undefined; entry = entry.mAfter) {
            entry.mValue = undefined;
            entry.mBefore = undefined;
            entry.mNext = undefined;
            if (entry.mPrevious == undefined)
                __classPrivateFieldGet(this, _mEnries)[entry.mIndex] = undefined;
            else
                entry.mPrevious = undefined;
        }
        if (__classPrivateFieldGet(this, _mLast) != undefined) {
            __classPrivateFieldGet(this, _mLast).mAfter = __classPrivateFieldGet(this, _mPool);
            __classPrivateFieldSet(this, _mPool, __classPrivateFieldGet(this, _mFirst));
            __classPrivateFieldSet(this, _mFirst, undefined);
            __classPrivateFieldSet(this, _mLast, undefined);
            __classPrivateFieldSet(this, _mSize, 0);
        }
    }
    isEmpty() {
        return __classPrivateFieldGet(this, _mSize) == 0;
    }
    size() {
        return __classPrivateFieldGet(this, _mSize);
    }
    capacity() {
        return __classPrivateFieldGet(this, _mCapacity);
    }
    toArray() {
        let sets = [];
        if (__classPrivateFieldGet(this, _mSize) <= 0)
            return sets;
        for (let i = 0; i < __classPrivateFieldGet(this, _mSize); i++)
            sets[i] = this.get(i);
        return sets;
    }
    toString() {
        let builder = new StringBuilder_js_1.StringBuilder();
        builder.append("{");
        let index = 0;
        for (let entry of this.entrySet()) {
            if (index > 0)
                builder.append(", ");
            builder.append(entry.toString());
            index++;
        }
        builder.append("}");
        return builder.toString();
    }
    clone() {
        let clone = new HashSetPool();
        if (__classPrivateFieldGet(this, _mSize) <= 0)
            return clone;
        clone.init(__classPrivateFieldGet(this, _mCapacity));
        clone.putAll(this);
        return clone;
    }
    hashCode() {
        let code = 0;
        for (let entry = __classPrivateFieldGet(this, _mFirst); entry != undefined; entry = entry.mAfter)
            code += entry.hashCode();
        return code;
    }
    equals(object) {
        if (object == this)
            return true;
        if (object instanceof HashSetPool) {
            if (this.size() != object.size())
                return false;
            for (let entry = __classPrivateFieldGet(this, _mFirst); entry != undefined; entry = entry.mNext) {
                if (!entry.equals(object.getEntryAt(entry.mIndex)))
                    return false;
            }
        }
        return false;
    }
    setCapacity(capacity) {
        if (capacity > __classPrivateFieldGet(this, _mCapacity)) {
            for (let i = 0; i < capacity; i++) {
                let entry = new SetPool_js_1.SetPool.Entry();
                entry.mAfter = __classPrivateFieldGet(this, _mPool);
                __classPrivateFieldSet(this, _mPool, entry);
            }
        }
        else if (capacity < __classPrivateFieldGet(this, _mCapacity)) {
            for (let i = capacity; (i < __classPrivateFieldGet(this, _mCapacity)) && (__classPrivateFieldGet(this, _mPool) != undefined); i++) {
                let entry = __classPrivateFieldGet(this, _mPool);
                __classPrivateFieldSet(this, _mPool, entry.mAfter);
                entry.mAfter = undefined;
            }
        }
        let lenght = 16;
        while (lenght < capacity) {
            lenght <<= 1;
        }
        if (__classPrivateFieldGet(this, _mEnries).length != lenght) {
            __classPrivateFieldSet(this, _mEnries, []);
            let entry = __classPrivateFieldGet(this, _mFirst);
            while (entry != undefined) {
                let index = this.indexHash(entry.mIndex);
                entry.mIndex = index;
                entry.mPrevious = undefined;
                let next = __classPrivateFieldGet(this, _mEnries)[index];
                entry.mNext = next;
                if (next != undefined)
                    next.mPrevious = entry;
                __classPrivateFieldGet(this, _mEnries)[index] = entry;
                entry = entry.mAfter;
            }
        }
        __classPrivateFieldSet(this, _mCapacity, capacity);
    }
    putEntry(value) {
        let entry = __classPrivateFieldGet(this, _mPool);
        if (entry != undefined) {
            __classPrivateFieldSet(this, _mPool, entry.mAfter);
            entry.mAfter = undefined;
        }
        else
            entry = new SetPool_js_1.SetPool.Entry();
        entry.mValue = value;
        let index = this.indexHash(__classPrivateFieldGet(this, _mSize));
        entry.mIndex = index;
        let next = __classPrivateFieldGet(this, _mEnries)[index];
        entry.mNext = next;
        if (next != undefined)
            next.mPrevious = entry;
        __classPrivateFieldGet(this, _mEnries)[index] = entry;
        if (__classPrivateFieldGet(this, _mLast) != undefined) {
            entry.mBefore = __classPrivateFieldGet(this, _mLast);
            __classPrivateFieldGet(this, _mLast).mAfter = entry;
        }
        else
            __classPrivateFieldSet(this, _mFirst, entry);
        __classPrivateFieldSet(this, _mLast, entry);
        __classPrivateFieldSet(this, _mSize, +__classPrivateFieldGet(this, _mSize) + 1);
        this.updateCapacity();
    }
    removeEntry(entry) {
        let previous = entry.mPrevious;
        let next = entry.mNext;
        if (previous != undefined) {
            previous.mNext = next;
            entry.mPrevious = undefined;
        }
        else
            __classPrivateFieldGet(this, _mEnries)[entry.mIndex] = next;
        if (next != undefined) {
            next.mPrevious = previous;
            entry.mNext = undefined;
        }
        let before = entry.mBefore;
        let after = entry.mAfter;
        if (before != undefined) {
            before.mAfter = after;
            entry.mBefore = undefined;
        }
        else
            __classPrivateFieldSet(this, _mFirst, after);
        if (after != undefined)
            after.mBefore = before;
        else
            __classPrivateFieldSet(this, _mLast, before);
        entry.mValue = undefined;
        entry.mAfter = __classPrivateFieldGet(this, _mPool);
        __classPrivateFieldSet(this, _mPool, entry);
        __classPrivateFieldSet(this, _mSize, +__classPrivateFieldGet(this, _mSize) - 1);
        this.updateCapacity();
    }
    init(capacity) {
        let length = 16;
        while (length < __classPrivateFieldGet(this, _mCapacity)) {
            length <<= 1;
        }
        __classPrivateFieldSet(this, _mEnries, []);
        __classPrivateFieldSet(this, _mCapacity, capacity);
        __classPrivateFieldSet(this, _mSize, 0);
        __classPrivateFieldSet(this, _mPool, undefined);
        __classPrivateFieldSet(this, _mFirst, undefined);
        __classPrivateFieldSet(this, _mLast, undefined);
        for (let i = 0; i < capacity; i++) {
            let entry = new SetPool_js_1.SetPool.Entry();
            entry.mAfter = __classPrivateFieldGet(this, _mPool);
            __classPrivateFieldSet(this, _mPool, entry);
            __classPrivateFieldGet(this, _mEnries)[this.indexHash(i)] = undefined;
        }
    }
    indexHash(index) {
        let code = Objects_js_1.Objects.hash(index);
        code += -(code << 9);
        code ^= (code >>> 14);
        code += (code << 4);
        code ^= (code >>> 10);
        return code;
    }
    obtainEntry(index) {
        return __classPrivateFieldGet(this, _mEnries)[this.indexHash(index)];
    }
    updateCapacity() {
        if (__classPrivateFieldGet(this, _mSize) > __classPrivateFieldGet(this, _mCapacity))
            this.setCapacity(__classPrivateFieldGet(this, _mCapacity) * 2);
    }
}
exports.HashSetPool = HashSetPool;
_mEnries = new WeakMap(), _mPool = new WeakMap(), _mFirst = new WeakMap(), _mLast = new WeakMap(), _mSize = new WeakMap(), _mCapacity = new WeakMap();
//# sourceMappingURL=HashSetPool.js.map